package com.huatai.datacenter.service.impl;

import com.huatai.common.util.JsonUtil;
import com.huatai.common.util.StringUtil;
import com.huatai.datacenter.entity.*;
import com.huatai.datacenter.entity.query.Queries;
import com.huatai.datacenter.entity.query.QueriesLast;
import com.huatai.datacenter.entity.query.Query;
import com.huatai.datacenter.entity.query.QueryLast;
import org.springframework.util.Assert;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @program: ht-system
 * @description: 公共接口
 * @author: songxiude
 * @create: 2023-04-25 15:00
 **/

public class BaseServiceImpl {

	private final String ROLLUP_RAW = "ROLLUP_RAW";

	/**
	 * 基础查询结构组合
	 * <p>
	 * {"start":"1596470400000","end":"1596504668404","queries":[{"aggregator":"none","metric":"Ua","downsample":"1h-max-","tags":{"equipCode":"119"}}]}
	 *
	 * @param querySingle 请求传入的参数
	 * @return 返回值
	 */
	public String composeQuery(QuerySingle querySingle) {
		String start = querySingle.getStart();
		String end = querySingle.getEnd();
		String rollupUsage = querySingle.getRollupUsage();
		String downSample = querySingle.getDownSample();
		String[] metrics = querySingle.getMetrics();
		String aggregator = StringUtil.isBlank(querySingle.getAggregator()) ? "none" : querySingle.getAggregator();
		String equipCode = querySingle.getEquipCode();
		Tags tags = new Tags();
		tags.setEquipCode(equipCode);
		List<Queries> queriesList = new ArrayList<>();
		for (String metric : metrics) {
			Queries queries = new Queries();
			queries.setAggregator(aggregator);
			queries.setDownsample(downSample);
			queries.setTags(tags);
			queries.setMetric(metric);
			queries.setRollupUsage(rollupUsage);
			queriesList.add(queries);
		}
		Query query = new Query(start, end, queriesList);
		return JsonUtil.toJson(query);
	}

	/**
	 * 多设备查询结构组合
	 * <p>
	 * {"start":"1596470400000","end":"1596504668404","queries":[{"aggregator":"none","metric":"Ua","downsample":"1h-max-","tags":{"equipCode":"119"}},{"aggregator":"none","metric":"Ub","downsample":"1h-max-","tags":{"equipCode":"119"}}]}
	 *
	 * @param queryMultiple 请求传入的参数
	 * @return 返回值
	 */
	public String composeQuery(QueryMultiple queryMultiple) {
		String start = queryMultiple.getStart();
		String end = queryMultiple.getEnd();
		String rollupUsage = queryMultiple.getRollupUsage();
		String downSample = queryMultiple.getDownSample();
		String aggregator = StringUtil.isBlank(queryMultiple.getAggregator()) ? "none" : queryMultiple.getAggregator();
		List<MultipleDevice> multipleDevices = queryMultiple.getMultipleDevices();
		List<Queries> queriesList = new ArrayList<>();
		multipleDevices.forEach(multipleDevice -> {
			Queries queries = new Queries();
			queries.setDownsample(downSample);
			queries.setAggregator(aggregator);
			queries.setRollupUsage(rollupUsage);
			queries.setTags(new Tags(multipleDevice.getEquipCode()));
			queries.setMetric(multipleDevice.getMetric());
			queriesList.add(queries);
		});
		Query query = new Query(start, end, queriesList);
		return JsonUtil.toJson(query);
	}

	/**
	 * 查询结构组合
	 * <p>
	 * {"resolveNames":true,"backScan":124,"queries":[{"metric":"Ua","tags":{"equipCode":"12839570163"}}]}
	 *
	 * @param queryLastSingle 请求传入的参数
	 * @return 返回值
	 */
	public String composeQueryLast(QueryLastSingle queryLastSingle) {
		boolean resolveNames = queryLastSingle.isResolveNames();
		Integer backScan = queryLastSingle.getBackScan();
		String[] metrics = queryLastSingle.getMetrics();
		String equipCode = queryLastSingle.getEquipCode();
		Tags tags = new Tags(equipCode);
		QueryLast query = new QueryLast();
		query.setBackScan(backScan);
		query.setResolveNames(resolveNames);
		List<QueriesLast> queryLastList = new ArrayList<>();
		query.setQueries(queryLastList);
		for (String metric : metrics) {
			QueriesLast queriesLast = new QueriesLast();
			queriesLast.setMetric(metric);
			queriesLast.setTags(tags);
			queryLastList.add(queriesLast);
		}
		return JsonUtil.toJson(query);
	}

	/**
	 * 查询结构组合
	 * <p>
	 * {"resolveNames":true,"backScan":124,"queries":[{"metric":"Ua","tags":{"equipCode":"12839570163"}}]}
	 *
	 * @param queryLastMultiple 请求传入的参数
	 * @return 返回值
	 */
	public String composeQueryLast(QueryLastMultiple queryLastMultiple) {
		boolean resolveNames = queryLastMultiple.isResolveNames();
		Integer backScan = queryLastMultiple.getBackScan();
		List<MultipleDevice> multipleDevices = queryLastMultiple.getMultipleDevices();
		List<QueriesLast> queryLastList = new ArrayList<>();
		QueryLast query = new QueryLast();
		query.setBackScan(backScan);
		query.setResolveNames(resolveNames);
		query.setQueries(queryLastList);
		multipleDevices.forEach(multipleDevice -> {
			QueriesLast queriesLast = new QueriesLast();
			queriesLast.setMetric(multipleDevice.getMetric());
			queriesLast.setTags(new Tags(multipleDevice.getEquipCode()));
			queryLastList.add(queriesLast);
		});
		return JsonUtil.toJson(query);
	}


	/**
	 * 写入结构组合
	 *
	 * @param putSingle 写入参数
	 * @return JSON字符串
	 */
	public String composePut(PutSingle putSingle) {
		String equipCode = putSingle.getEquipCode();
		String metric = putSingle.getMetric();
		Long timestamp = putSingle.getTimestamp();
		Double value = putSingle.getValue();
		boolean difference = putSingle.isDifference();
		return composePut(equipCode, metric, timestamp, value, difference);
	}

	/**
	 * 汇总数据写入格式
	 *
	 * @param rollupPutSingle
	 * @return
	 */
	public String composePut(RollupPutSingle rollupPutSingle) {
		String equipCode = rollupPutSingle.getEquipCode();
		String metric = rollupPutSingle.getMetric();
		String aggregator = rollupPutSingle.getAggregator();
		String interval = rollupPutSingle.getInterval();
		Long timestamp = rollupPutSingle.getTimestamp();
		Double value = rollupPutSingle.getValue();
		Put put = new Put(metric, aggregator, interval, timestamp, value, new Tags(equipCode));
		return JsonUtil.toJson(put);
	}

	/**
	 * 汇总数据批量写入
	 *
	 * @param rollupPutSingles
	 * @return
	 */
	public String rollupPutList(List<RollupPutSingle> rollupPutSingles) {
		List<Put> putList = new ArrayList<>();
		rollupPutSingles.forEach(putSingle -> {
			String equipCode = putSingle.getEquipCode();
			String metric = putSingle.getMetric();
			String aggregator = putSingle.getAggregator();
			String interval = putSingle.getInterval();
			Long timestamp = putSingle.getTimestamp();
			Double value = putSingle.getValue();
			Put put = new Put(metric, aggregator, interval, timestamp, value, new Tags(equipCode));
			putList.add(put);
		});
		return JsonUtil.toJson(putList);
	}


	/**
	 * 写入结构组合
	 *
	 * @param putSingle 写入参数
	 * @return JSON字符串
	 */
	public String composePutList(List<PutSingle> putSingle) {
		return composePut(putSingle);
	}

	/**
	 * 写入结构组合
	 *
	 * @param querySingle 基础查询对象
	 * @return JSON字符串
	 */
	public String composePut(QuerySingle querySingle) {
		@NotNull String[] metrics = querySingle.getMetrics();
		@NotBlank String equipCode = querySingle.getEquipCode();
		return composePut(metrics, equipCode);
	}

	/**
	 * 多设备写入结构组合
	 *
	 * @param queryMultiple 基础查询对象
	 * @return JSON字符串
	 */
	public String composePut(QueryMultiple queryMultiple) {
		@NotNull List<MultipleDevice> multipleDevices = queryMultiple.getMultipleDevices();
		return composeMultiplePut(multipleDevices);
	}

	/**
	 * 写入结构组合
	 *
	 * @param queryLastSingle 基础查询对象
	 * @return JSON字符串
	 */
	public String composePut(QueryLastSingle queryLastSingle) {
		@NotNull String[] metrics = queryLastSingle.getMetrics();
		@NotBlank String equipCode = queryLastSingle.getEquipCode();
		return composePut(metrics, equipCode);
	}

	/**
	 * 写入结构组合
	 *
	 * @param queryLastMultiple 写入对象
	 * @return JSON字符串
	 */
	public String composePut(QueryLastMultiple queryLastMultiple) {
		List<MultipleDevice> multipleDevices = queryLastMultiple.getMultipleDevices();
		return composeMultiplePut(multipleDevices);
	}

	/**
	 * 写入结构组合
	 * <p>
	 * [{"metric":"Ia","timestamp":1,"value":0,"tags":{"equipCode":"1239"}},{"metric":"Ic","timestamp":1,"value":0,"tags":{"equipCode":"1239"}}]
	 *
	 * @param metrics   量测编码
	 * @param equipCode 设备编码
	 * @return JSON字符串
	 */
	private String composePut(String[] metrics, String equipCode) {
		Tags tags = new Tags();
		tags.setEquipCode(equipCode);
		List<Put> putList = new ArrayList<>();
		for (String metric : metrics) {
			Put put = new Put(metric, 1L, 0.0, tags);
			putList.add(put);
		}
		return JsonUtil.toJson(putList);
	}

	/**
	 * 写入结构组合
	 * <p>
	 * [{"metric":"Ia","timestamp":1,"value":0,"tags":{"equipCode":"1239"}},{"metric":"Ic","timestamp":1,"value":0,"tags":{"equipCode":"1239"}}]
	 *
	 * @param multipleDevices 多设备信息
	 * @return JSON字符串
	 */
	private String composeMultiplePut(List<MultipleDevice> multipleDevices) {
		List<Put> putList = new ArrayList<>();
		multipleDevices.forEach(multipleDevice -> {
			String metric = multipleDevice.getMetric();
			String equipCode = multipleDevice.getEquipCode();
			Put put = new Put(metric, 1L, 0.0, new Tags(equipCode));
			putList.add(put);
		});
		return JsonUtil.toJson(putList);
	}

	/**
	 * 写入结构组合
	 */
	private String composePut(String equipCode, String metric, Long timestamp, Double value) {
		Put put = new Put(metric, timestamp, value, new Tags(equipCode));
		return JsonUtil.toJson(put);
	}

	/**
	 * 写入结构组合
	 */
	private String composePut(String equipCode, String metric, Long timestamp, Double value, boolean difference) {
		Put put = new Put(metric, timestamp, value, new Tags(equipCode, difference));
		return JsonUtil.toJson(put);
	}

	/**
	 * 写入结构组合
	 * <p>
	 * [{"metric":"Ia","timestamp":1,"value":0,"tags":{"equipCode":"1239"}},{"metric":"Ic","timestamp":1,"value":0,"tags":{"equipCode":"1239"}}]
	 *
	 * @param putSingleList 写入集合
	 * @return JSON字符串
	 */
	private String composePut(List<PutSingle> putSingleList) {
		List<Put> putList = new ArrayList<>();
		putSingleList.forEach(putSingle -> {
			String equipCode = putSingle.getEquipCode();
			String metric = putSingle.getMetric();
			Long timestamp = putSingle.getTimestamp();
			Double value = putSingle.getValue();
			Put put = new Put(metric, timestamp, value, new Tags(equipCode));
			putList.add(put);
		});
		return JsonUtil.toJson(putList);
	}

	/**
	 * 将结果改为两位小数
	 *
	 * @param response 大数据查询结果集
	 */
	public List<QueryReturn> queryTwoDecimalPlaces(List<QueryReturn> response) {
		response.forEach(result -> {
			LinkedHashMap<String, Double> map = new LinkedHashMap<>();
			result.getDps().forEach((key, value) -> {
				if (value != null) {
					map.put(key, BigDecimal.valueOf(value).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
				} else {
					map.put(key, value);
				}
			});
			result.setDps(map);
		});
		return response;
	}


	/**
	 * 将未拥有的数据写回集合
	 *
	 * @return 查询结果
	 */
	public List<QueryReturn> writeIsNull(List<QueryReturn> response, QueryMultiple queryMultiple) {
		List<MultipleDevice> having = new ArrayList<>();
		queryMultiple.getMultipleDevices().forEach(multiple -> {
			String equipCode = multiple.getEquipCode();
			String metric = multiple.getMetric();
			response.forEach(result -> {
				if (result.getTags().getEquipCode().equals(equipCode) && metric.equals(result.getMetric())) {
					having.add(new MultipleDevice(equipCode, metric));
				}
			});
		});
		List<QueryReturn> noHavingReturn = new ArrayList<>(response);
		queryMultiple.getMultipleDevices().removeIf(having::contains);
		queryMultiple.getMultipleDevices().forEach(noHaving -> {
			QueryReturn queryReturn = new QueryReturn();
			queryReturn.setTags(new Tags(noHaving.getEquipCode()));
			queryReturn.setMetric(noHaving.getMetric());
			noHavingReturn.add(queryReturn);
		});
		return noHavingReturn;
	}

	/**
	 * 将未拥有的数据写回集合
	 *
	 * @return 查询结果
	 */
	public List<QueryReturn> writeIsNull(List<QueryReturn> response, QuerySingle querySingle) {
		List<String> metricList = new ArrayList<>(Arrays.asList(querySingle.getMetrics()));
		List<String> having = new ArrayList<>();
		String equipCode = querySingle.getEquipCode();
		response.forEach(result -> {
			String queryEquipCode = result.getTags().getEquipCode();
			String metric = result.getMetric();
			if (queryEquipCode.equals(equipCode) && metricList.contains(metric)) {
				having.add(metric);
			}
		});
		List<QueryReturn> noHavingReturn = new ArrayList<>(response);
		List<String> metrics = new ArrayList<>(metricList);
		metrics.removeIf(having::contains);
		metrics.forEach(noHaving -> {
			QueryReturn queryReturn = new QueryReturn();
			queryReturn.setTags(new Tags(equipCode));
			queryReturn.setMetric(noHaving);
			queryReturn.setDps(new LinkedHashMap<>());
			queryReturn.setAggregateTags(new ArrayList<>());
			noHavingReturn.add(queryReturn);
		});
		return noHavingReturn;
	}

	/**
	 * 将未拥有的数据写回集合
	 *
	 * @return 查询结果
	 */
	public List<QueryLastReturn> writeIsNull(List<QueryLastReturn> response, QueryLastMultiple queryLastMultiple) {
		List<MultipleDevice> having = new ArrayList<>();
		queryLastMultiple.getMultipleDevices().forEach(multiple -> {
			String equipCode = multiple.getEquipCode();
			String metric = multiple.getMetric();
			response.forEach(result -> {
				if (result.getTags().getEquipCode().equals(equipCode) && metric.equals(result.getMetric())) {
					having.add(new MultipleDevice(equipCode, metric));
				}
			});
		});
		List<QueryLastReturn> noHavingReturn = new ArrayList<>(response);
		List<MultipleDevice> deviceList = new ArrayList<>(queryLastMultiple.getMultipleDevices());
		deviceList.removeIf(having::contains);
		deviceList.forEach(noHaving -> {
			QueryLastReturn lastReturn = new QueryLastReturn();
			lastReturn.setTags(new Tags(noHaving.getEquipCode()));
			lastReturn.setMetric(noHaving.getMetric());
			noHavingReturn.add(lastReturn);
		});
		return noHavingReturn;
	}

	/**
	 * 将未拥有的数据写回集合
	 *
	 * @return 查询结果
	 */
	public List<QueryLastReturn> writeIsNull(List<QueryLastReturn> response, QueryLastSingle queryLastSingle) {
		List<String> metricList = new ArrayList<>(Arrays.asList(queryLastSingle.getMetrics()));
		List<String> having = new ArrayList<>();
		String equipCode = queryLastSingle.getEquipCode();
		response.forEach(result -> {
			String queryEquipCode = result.getTags().getEquipCode();
			String metric = result.getMetric();
			if (queryEquipCode.equals(equipCode) && metricList.contains(metric)) {
				having.add(metric);
			}
		});
		List<QueryLastReturn> noHavingReturn = new ArrayList<>(response);
		List<String> returnList = new ArrayList<>(metricList);
		returnList.removeIf(having::contains);
		returnList.forEach(noHaving -> {
			QueryLastReturn queryReturn = new QueryLastReturn();
			queryReturn.setTags(new Tags(equipCode));
			queryReturn.setMetric(noHaving);
			noHavingReturn.add(queryReturn);
		});
		return noHavingReturn;
	}


	/**
	 * 将结果改为两位小数
	 *
	 * @param response 大数据查询结果集
	 */
	public List<QueryLastReturn> lastTwoDecimalPlaces(List<QueryLastReturn> response) {
		response.forEach(result -> result.setValue(String.valueOf(BigDecimal.valueOf(Double.parseDouble(result.getValue())).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue())));
		return response;
	}


	/**
	 * 校验开始时间与结束时间的参数是否正确
	 *
	 * @param start 开始时间
	 * @param end   结束时间
	 */
	private void checkParam(Object start, Object end) {
		if (start instanceof Double || end instanceof Double ||
			start instanceof Long || end instanceof Long ||
			start instanceof String || end instanceof String ||
			start instanceof LocalDateTime || end instanceof LocalDateTime) {
			return;
		}
		Assert.isTrue(false, "参数出现错误");
	}

	/**
	 * 计算差值查询
	 */
	public String composeQueryDifference(QuerySingle querySingle) {
		String start = querySingle.getStart();
		String end = querySingle.getEnd();
		String rollupUsage = querySingle.getRollupUsage();
		String downSample = querySingle.getDownSample();
		String[] metrics = querySingle.getMetrics();
		String aggregator = StringUtil.isBlank(querySingle.getAggregator()) ? "none" : querySingle.getAggregator();
		String equipCode = querySingle.getEquipCode();
		boolean difference = querySingle.isDifference();
		Tags tags = new Tags();
		tags.setEquipCode(equipCode);
		if (difference) {
			tags.setDifference(true);
		}
		List<Queries> queriesList = new ArrayList<>();
		for (String metric : metrics) {
			Queries queries = new Queries();
			queries.setAggregator(aggregator);
			queries.setDownsample(downSample);
			queries.setTags(tags);
			queries.setMetric(metric);
			queries.setRollupUsage(rollupUsage);
			queriesList.add(queries);
		}
		Query query = new Query(start, end, queriesList);
		return JsonUtil.toJson(query);
	}


}
